package ee122Networking;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.List;

public class RouterReceiverThread extends Thread {
	static int _PORT_NUMBER = 9000;
	protected DatagramSocket socket;
	protected List<byte[]> internalStorage;
	protected List<byte[]> priorityStorage = null;
	protected int priorityDestination;
	
	public RouterReceiverThread (List<byte[]> internalStorage) {
		this.internalStorage = internalStorage;
		try {
			socket = new DatagramSocket(_PORT_NUMBER);
		} catch (SocketException e) {
			System.out.println("Socket could not be opened on port " + _PORT_NUMBER);
			e.printStackTrace();
		}
		System.out.println("Router socket opened. Listening on port " + socket.getLocalPort());
	}
	
	public RouterReceiverThread (List<byte[]> internalStorage, List<byte[]> priorityStorage, int priorityDestination) {
		this(internalStorage);
		this.priorityStorage = priorityStorage;
		this.priorityDestination = priorityDestination;
	}
	
	public void run() {
		byte[] buf = new byte[128];
		DatagramPacket packet;
		while(true) {
			buf = new byte[128];
			packet = new DatagramPacket(buf, buf.length);
			try {
				socket.receive(packet);
			} catch (IOException e) {
				e.printStackTrace();
				continue;
			}	
			System.arraycopy(packet.getData(), packet.getOffset(), buf, 0, packet.getLength());
			
			int seqno = 0;
			byte[] seqnoData = new byte[4];
			System.arraycopy(buf, 0, seqnoData, 0, 4);
			ByteArrayInputStream bis = new ByteArrayInputStream(seqnoData);
			DataInputStream dis = new DataInputStream(bis);
			try {
				seqno = dis.readInt();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			// get the packet's Destination
			int packetDestination = 0;
			byte[] destPortData = new byte[4];
			System.arraycopy(buf, 4, destPortData, 0, 4);
			bis = new ByteArrayInputStream(destPortData);
			dis = new DataInputStream(bis);
			try {
				packetDestination = dis.readInt();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			// if we're taking priority of one receiver over another, use the priority storage
			// for the one we want to give more attention to. Synchronize both lists since
			// we want to make sure that we don't have more than 64 packets in the router
			// at one time.
			// Otherwise, just use the internalStorage like normal
			
			if (priorityStorage != null) {
				System.out.println("checking priorityStorage: packet Destination " + packetDestination + " priorityDestination " + priorityDestination + " match? " + (priorityDestination == packetDestination));
				if (packetDestination == priorityDestination) {
					synchronized(internalStorage) {
						synchronized(priorityStorage) {
							// only add the packet if there is room in the storage
							if (internalStorage.size() + priorityStorage.size() < 64) {
								priorityStorage.add(buf);
								System.out.println("Added to priority Storage");
								System.out.println("Router Storage has " + (internalStorage.size()+priorityStorage.size())  +" packets. From port " + packet.getPort() + " with seq.no " + seqno);
							} else if(internalStorage.size()>1) { 
								
								internalStorage.remove(0);
								priorityStorage.add(buf);
								System.out.println("Dropped packet from S2");
							}else{
								
							}
						}
					}
				} else {
					synchronized(internalStorage) {
						synchronized(priorityStorage) {
							// only add the packet if there is room in the storage
							if (internalStorage.size() + priorityStorage.size() < 64) {
								internalStorage.add(buf);
								System.out.println("Added to internal Storage");
								System.out.println("Router Storage has " + (internalStorage.size()+priorityStorage.size())  +" packets. From port " + packet.getPort() + " with seq.no " + seqno);
							} else if(!internalStorage.isEmpty()) {
								internalStorage.remove(0);
								internalStorage.add(buf);
								System.out.println("Dropped packet from port "+ packet.getPort() + " with seq.no " + seqno);
							}
						}
					}
				}
			} else {
				synchronized(internalStorage) {
					// only add the packet if there is room in the storage
					if (internalStorage.size() < 64) {
						internalStorage.add(buf);
						System.out.println("internalStorage has " + internalStorage.size() +" packets. From port " + packet.getPort() + " with seq.no " + seqno);
					} else { 
						System.out.println("Dropped packet from port "+ packet.getPort() + " with seq.no " + seqno);
					}
				}
			}
		}
	}
}
